package com.miniapp.design.aop;

import com.miniapp.context.UserContext;
import com.miniapp.entity.Permission;
import com.miniapp.handler.exception.PermissionDeniedException;
import com.miniapp.service.PermissionService;
import com.miniapp.service.RoleService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author author
 * @date 2025-09-08 14:18
 */
@Aspect
@Component
public class PermissionAspect {

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    /**
     * 拦截所有标注了@RequiresRoles注解的方法
     */
    @Before("@annotation(com.miniapp.design.aop.RequiresRoles)")
    public void checkRolePermission(JoinPoint joinPoint) {
        // 获取当前请求
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            throw new PermissionDeniedException("无法获取请求上下文");
        }
        HttpServletRequest request = attributes.getRequest();

        // 获取当前登录用户ID
        Long userId = getCurrentUserId(request);
        if (userId == null) {
            throw new PermissionDeniedException("用户未登录");
        }

        // 获取方法上的注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class);

        // 获取用户拥有的角色
        List<String> userRoles = roleService.getUserRoleCodes(userId);
        Set<String> userRoleSet = userRoles.stream().collect(Collectors.toSet());

        // 获取接口所需角色
        String[] requiredRoles = requiresRoles.value();
        boolean allRequired = requiresRoles.all();

        // 校验权限
        if (allRequired) {
            // 需要所有角色
            for (String role : requiredRoles) {
                if (!userRoleSet.contains(role)) {
                    throw new PermissionDeniedException("缺少必要角色: " + role);
                }
            }
        } else {
            // 需要至少一个角色
            boolean hasPermission = false;
            for (String role : requiredRoles) {
                if (userRoleSet.contains(role)) {
                    hasPermission = true;
                    break;
                }
            }
            if (!hasPermission) {
                throw new PermissionDeniedException("没有访问权限，需要以下任一角色: " + String.join(",", requiredRoles));
            }
        }
    }

    /**
     * 拦截所有标注了@RequiresPermissions注解的方法
     */
    @Before("@annotation(com.miniapp.design.aop.RequiresPermissions)")
    public void checkPermission(JoinPoint joinPoint) {
        // 获取当前请求
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            throw new PermissionDeniedException("无法获取请求上下文");
        }
        HttpServletRequest request = attributes.getRequest();

        // 获取当前登录用户ID
        Long userId = getCurrentUserId(request);
        if (userId == null) {
            throw new PermissionDeniedException("用户未登录");
        }

        // 获取方法上的注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);

        // 获取用户拥有的角色ID
        List<Long> roleIds = roleService.getUserRoleIds(userId);

        // 获取用户拥有的权限
        List<Permission> permissions = permissionService.getPermissionsByRoleIds(roleIds);
        Set<String> permissionSet = permissions.stream()
                .map(Permission::getPermissionCode)
                .collect(Collectors.toSet());

        // 获取接口所需权限
        String[] requiredPermissions = requiresPermissions.value();
        boolean allRequired = requiresPermissions.all();

        // 校验权限
        if (allRequired) {
            // 需要所有权限
            for (String permission : requiredPermissions) {
                if (!permissionSet.contains(permission)) {
                    throw new PermissionDeniedException("缺少必要权限: " + permission);
                }
            }
        } else {
            // 需要至少一个权限
            boolean hasPermission = false;
            for (String permission : requiredPermissions) {
                if (permissionSet.contains(permission)) {
                    hasPermission = true;
                    break;
                }
            }
            if (!hasPermission) {
                throw new PermissionDeniedException("没有访问权限，需要以下任一权限: " + String.join(",", requiredPermissions));
            }
        }
    }

    /**
     * 从请求中获取当前登录用户ID
     */
    private Long getCurrentUserId(HttpServletRequest request) {
        return UserContext.getUserId();
    }
}